from app.log.log import logger

from fastapi.responses import JSONResponse
from tortoise.functions import Max, Sum
from tortoise.transactions import in_transaction

from app.controllers.system.user import user_controller
from app.models import Deposit, Integral, Coupons, Commission, CouponsRole, LevelIntegral
from app.schemas.marketing import CouponsCreate
from app.schemas.users import UserCreate
from app.settings import settings
from app.core.crud import CRUDBase
from app.models.customer import CustomerUser, CustomerLevel
from app.schemas.customer import *
from app.utils.password import get_password_hash, verify_password
from fastapi.exceptions import HTTPException
from tortoise.expressions import Q
import base64
import json
from Crypto.Cipher import AES
from datetime import timedelta, timezone
from app.utils.jwt import create_customer_token


class UsersController(CRUDBase[CustomerUser, CustomerUserCreate, CustomerUserUpdate]):
    def __init__(self):
        super().__init__(model=CustomerUser)

    async def create_user(self, obj_in: CustomerUserCreate) -> CustomerUser:
        #obj_in.password = get_password_hash(password=obj_in.password)
        # 自动生成卡号,按照目前最大卡号+1.annotate(max_price=Max('price')).values('max_price').first()
        ret_max_no = await self.model.annotate(max_no=Max("card_no")).first().values('max_no')
        if ret_max_no["max_no"] is not None:
            max_no = ret_max_no["max_no"] + 1
        else:
            max_no = 1
        # 关联数据
        if obj_in.parent is not None and obj_in.parent != 0:
            parent = await self.model.get(id=obj_in.parent)
            if parent:
                obj_in.parent = parent
            else:
                obj_in.parent = None
        obj_in.card_no = max_no
        obj = await self.create(obj_in)
        return obj

    async def update_user(self, obj_in: CustomerUserUpdate) -> CustomerUser:
        #关联数据
        if obj_in.parent is not None:
            parent = await self.model.get(id=obj_in.parent)
            if parent:
                obj_in.parent = parent
            else:
                obj_in.parent = None
        else:
            obj_in.parent = None
        if obj_in.is_user:
            ret = await user_controller.model.filter(id=obj_in.user_id).first()
            # 查询是否有系统用户账号
            if ret is None:
                user_in = UserCreate(
                    email=obj_in.phone+'@qq.com',
                    username=str(obj_in.phone),
                    password='123456',
                    is_active=True,
                    is_superuser=False,
                )
                # 系统用户生成
                uid = await user_controller.create_user(obj_in=user_in)
                # 设置角色权限为员工
                role_ids = [2]
                await user_controller.update_roles(uid, role_ids)
                obj_in.user_id = uid.id

        obj = await self.update(id=obj_in.id, obj_in=obj_in)
        return obj

    async def update_last_login(self, id: int) -> None:
        user = await self.model.get(id=id)
        user.last_login = datetime.now()
        await user.save()

    async def reset_password(self, user_id: int):
        user_obj = await self.get(id=user_id)
        user_obj.password = get_password_hash(password="123456")
        await user_obj.save()

    async def get_detail(self, user_id: int):
        user_obj = await self.get(id=user_id)
        user_obj.password = None

        return user_obj

    async def level_list(self):
        objs = await CustomerLevel.all().order_by("value").values("id", "name", "value")
        data = dict()
        for obj in objs:
            data[obj['value']] = obj['name']
        return data

    async def list_customer_down(self, search: Q = Q()):
        objs = await self.model.filter(search).all().values("id", "name", "card_no")
        # data = [await obj.to_dict() for obj in objs]
        data = []
        for obj in objs:
            data.append({"value": obj['id'], "label": obj['name'] + "[" + str(obj['card_no']) + "]"})
        return data

    async def authenticate(self, credentials: CredentialsSchema) -> Optional["CustomerUser"]:
        user = await self.model.filter(phone=credentials.name).first()
        if not user:
            raise HTTPException(status_code=400, detail="无效的用户名")
        if not credentials.password == "230307":
            # verified = verify_password(credentials.password, user.password)
            # if not verified:
            raise HTTPException(status_code=400, detail="密码错误!")
        if not user.is_active:
            raise HTTPException(status_code=400, detail="用户已被禁用")
        return user

    async def decrypt_user_phone(self, encrypted_data: str, session_key: str, iv: str) -> str:
        # Base64 decode
        encrypted_data = base64.b64decode(encrypted_data)
        session_key = base64.b64decode(session_key)
        iv = base64.b64decode(iv)
        # AES 解密
        cipher = AES.new(session_key, AES.MODE_CBC, iv)
        decrypted = cipher.decrypt(encrypted_data)
        # 去除填充
        decrypted = self.unpad(decrypted)
        # 转换为字典
        data = json.loads(decrypted.decode('utf-8'))
        return data

    def unpad(self, s: bytes) -> bytes:
        """去除填充"""
        padding_len = s[-1]
        return s[:-padding_len]

    async def mini_login(self, weichatlogin: CustomerWeichatLogin):
        #查询是否存在用户
        user = await CustomerUser.filter(phone=weichatlogin.phone).first()
        if user is None:
            #注册
            try:
                async with in_transaction() as transaction:
                    # 注册
                    data = {
                        "name": "微信用户",
                        "phone": weichatlogin.phone,
                        "parent": weichatlogin.user_id,
                        "open_id": weichatlogin.open_id
                    }

                    obj_in = CustomerUserCreate(**data)
                    ret = await self.create_user(obj_in)
                    if ret:
                        logger.info(f"获得邀请奖励优惠券")
                        # Import here to avoid circular dependency
                        from app.controllers.marketing.coupons import coupons_controller
                        coupons_data = CouponsCreate(
                            user_id=ret.id,
                            coupons_id=8,
                            coupons_price=0,
                            expire_at="",
                            is_used=0,
                            come_type=4,
                            add_order_id=0,
                            order_goods_id=0,
                            remark=f"新用户注册邀请奖励"
                        )
                        await coupons_controller.do_create(obj_in=coupons_data)
            except Exception as e:
                return JSONResponse(content={"code": 400, "message": f"创建过程中发生错误{e}"}, status_code=400)
        else:
            await CustomerUser.filter(phone=weichatlogin.phone).update(open_id=weichatlogin.open_id)
        data = {
            "name": weichatlogin.phone,
            "password": "230307",
        }
        credentials = CredentialsSchema(**data)
        ret = await self.get_token(credentials)
        return ret

    async def get_token(self, credentials: CredentialsSchema):
        user: CustomerUser = await self.authenticate(credentials)
        await self.update_last_login(user.id)
        access_token_expires = timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES)
        expire = datetime.now(timezone.utc) + access_token_expires
        data = CustomerJWTOut(
            access_token=create_customer_token(
                data=CustomerJWTPayload(
                    user_id=user.id,
                    username=user.name,
                    exp=expire,
                )
            ),
            username=user.name,
        )
        return data.model_dump()

    ##更新资产
    async def update_money(self, type: int, user_id: int):
        money = 0.00
        if type == 1:
            ##储值金
            result = await Deposit.filter(user_id=user_id, direction=1).annotate(
                add_price=Sum('price')
            ).first()
            add_price = result.add_price if result.add_price else 0.00
            result = await Deposit.filter(user_id=user_id, direction=2).annotate(
                del_price=Sum('price')
            ).first()
            del_price = result.del_price if result.del_price else 0.00
            money = round(float(add_price) - float(del_price), 2)
            await CustomerUser.filter(id=user_id).update(money_deposit=money)

        elif type == 2:
            ##积分
            result = await Integral.filter(user_id=user_id, direction=1).annotate(
                add_price=Sum('price')
            ).first()
            add_price = result.add_price if result.add_price else 0.00
            result = await Integral.filter(user_id=user_id, direction=2).annotate(
                del_price=Sum('price')
            ).first()
            del_price = result.del_price if result.del_price else 0.00
            money = round(float(add_price) - float(del_price), 2)
            await CustomerUser.filter(id=user_id).update(money_integral=money)

        elif type == 3:
            ##优惠券
            result = await Coupons.filter(user_id=user_id, is_used=0).annotate(
                add_price=Sum('coupons_price')
            ).first()
            money = result.add_price if result.add_price else 0.00
            await CustomerUser.filter(id=user_id).update(money_coupons=money)

        elif type == 4:
            ##佣金
            result = await Commission.filter(user_id=user_id).annotate(
                add_price=Sum('price')
            ).first()
            money = result.add_price if result.add_price else 0.00
            await CustomerUser.filter(id=user_id).update(money_commission=money)

        elif type == 5:
            ##等级积分
            result = await LevelIntegral.filter(user_id=user_id, direction=1).annotate(
                add_price=Sum('price')
            ).first()
            add_price = result.add_price if result.add_price else 0.00
            result = await LevelIntegral.filter(user_id=user_id, direction=2).annotate(
                del_price=Sum('price')
            ).first()
            del_price = result.del_price if result.del_price else 0.00
            money = round(float(add_price) - float(del_price), 2)
            await CustomerUser.filter(id=user_id).update(level_integral=money)
            ##这里还要查询客户是否升级
            level_data = await CustomerLevel.filter(level_integral__lte=money).order_by("-value").first().values("value")
            if level_data:
                await CustomerUser.filter(id=user_id).update(role_id=level_data['value'])
        return money

    async def get_visit(self,page: int, page_size: int, user_id: int):
        query = self.model.filter(parent_id=user_id)
        total = await query.count()
        objs = await query.offset((page - 1) * page_size).limit(page_size).order_by("-id")
        data = [await obj.to_dict() for obj in objs]
        return total,data

users_controller = UsersController()
